/*
   Copyright (C) 2006
   Andrew Madigan

This file is part of nhttpd.

nhttpd is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

nhttpd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with nhttpd; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version.
*/

#ifndef NQUEUE_H
#define NQUEUE_H
#include <nhttpd/list.h>
#include <nhttpd/hashtable.h>
#include <sys/types.h>
#define NANOS_PER_SEC 1000000

/*
Queues for NHTTPD, how these are implemented is dependent on runtime detection
of features.
*/

/*
There are two types of blocking queue, one is used with multiple threads that 
work with similar data in different ways, the other is for multiple identical
threads. Only the second type of queue can use timeouts.
*/

#include "detect.h"

/*
If threading is off, callbacks are used instead, this is the definition for 
callbacks.
*/
typedef void (*NHQ_Handler)(void* ptr, void* value);

typedef enum {NHQ_BLOCK, NHQ_NOBLOCK} NHQ_Flag;

#if NH_XMQ == 0 || NH_THREADS == 0
#define NH_GQ_DETECT
#endif

typedef struct {
	Hashtable* table;
	void* ptr;
} NH_GQ_PQH;

typedef struct {
  Object super;
  union {
#if NH_XMQ >= 0 && NH_THREADS >= 0
	 int mqid;
#endif
#if NH_XMQ <= 0 || NH_THREADS <= 0
	NH_GQ_PQH pqh;
#endif
  } data;
  int maxqueued;
} GroupQueue;



#ifdef NH_GQ_DETECT
extern GroupQueue* (*GQ_Create)(int maxqueued, void* ptr);
extern void (*GQ_SetCallback)(GroupQueue* self, int type, NHQ_Handler callback);
extern bool (*GQ_Enqueue)(GroupQueue* self, void* value, int type, 
	NHQ_Flag flag);
extern void* (*GQ_Dequeue)(GroupQueue* self, int type, NHQ_Flag flag);
#else
GroupQueue* GQ_Create(int maxqueued, void* ptr);
void GQ_SetCallback(GroupQueue* self, int type, NHQ_Handler callback);
bool GQ_Enqueue(GroupQueue* self, void* value, int type, NHQ_Flag flag);
void* GQ_Dequeue(GroupQueue* self, int type, NHQ_Flag flag);
#endif

typedef struct {
  pthread_cond_t consumedCondition;
  pthread_cond_t producedCondition;
  pthread_mutex_t mutex;
  int maxqueued;
  List* list;
} PQ_ThreadQueue;

#if NH_THREADS == 0
#define NH_PQ_DETECT
#endif

#if NH_THREADS <= 0
typedef struct {
	NHQ_Handler callback;
	void* ptr;
} NH_PQ_CB;
#endif

typedef struct {
  Object super;
  union {
#if NH_THREADS >= 0
	 PQ_ThreadQueue* queue;
#endif
#if NH_THREADS <= 0
	NH_PQ_CB cb;
#endif
	} data;
} PoolQueue;

#define PQ_BLOCK 0
#define PB_NOBLOCK 1

#ifdef NH_PQ_DETECT
extern PoolQueue* (*PQ_Create)(int maxqueued, NHQ_Handler callback, void* ptr);
extern bool (*PQ_Enqueue)(PoolQueue* self, void* value, NHQ_Flag flag);
extern void* (*PQ_Dequeue)(PoolQueue* self, NHQ_Flag flag);
#else
PoolQueue* PQ_Create(int maxqueued, NHQ_Handler callback, void* ptr);
bool PQ_Enqueue(PoolQueue* self, void *value, NHQ_Flag flag);
void* PQ_Dequeue(PoolQueue* self, NHQ_Flag flag);
#endif

#if NH_TIMEOUTS == 0 || defined NH_PQ_DETECT
extern bool (*PQ_TimedEnqueue)(PoolQueue* self, long nanos, void* value, 
	NHQ_Flag altflag);
extern void* (*PQ_TimedDequeue)(PoolQueue* self, long nanos, NHQ_Flag altflag);
#else
bool PQ_TimedEnqueue(PoolQueue* self, long nanos, void* value, NHQ_Flag altflag);
void* PQ_TimedDequeue(PoolQueue* self, long nanos, NHQ_Flag altflag);
#endif

void NHQ_init();

#endif
